/*!
 * @file        qpm32f10x_qspi.c
 *
 * @brief       This file contains all the functions for the QSPI peripheral
 *
 * @version     V1.0.0
 *
 * @date        2020-3-26
 *
 */
#include "apm32f10x_qspi.h"

/** @addtogroup Peripherals_Library Standard Peripheral Library  
  @{
*/

/** @addtogroup QSPI_Driver  QSPI Driver
  @{
*/

/** @addtogroup  QSPI_Fuctions Fuctions
  @{
*/

/*!
 * @brief       Set QSPI peripheral registers to their default reset values
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_Reset(void)
{
    volatile uint32_t dummy = 0;
    
    QSPI->SSIEN = QSPI_SSIEN_RESET_VALUE;
    QSPI->INTEN = QSPI_INTEN_RESET_VALUE;
    dummy = QSPI->INTCLR;
    QSPI->CTRL0 = QSPI_CTRL0_RESET_VALUE;
    QSPI->CTRL1 = QSPI_CTRL1_RESET_VALUE;
    QSPI->CTRL2 = QSPI_CTRL2_RESET_VALUE;
    QSPI->SLAEN = QSPI_SLAEN_RESET_VALUE;
    QSPI->BR = QSPI_BR_RESET_VALUE;
    QSPI->TFL = QSPI_TFL_RESET_VALUE;
    QSPI->RFL = QSPI_RFL_RESET_VALUE;
    QSPI->TFTL = QSPI_TFTL_RESET_VALUE;
    QSPI->RFTL = QSPI_RFTL_RESET_VALUE;
    QSPI->STS = QSPI_STS_RESET_VALUE;
    QSPI->RSD = QSPI_RSD_RESET_VALUE;
    QSPI->IOSW = QSPI_IOSW_RESET_VALUE;
}

/*!
 * @brief       Config the QSPI peripheral according to the specified parameters in the configStruct
 *
 * @param       configStruct:   Pointer to a QSPI_ConfiStruct_T structure that contains the configuration information
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_Config(QSPI_ConfiStruct_T * configStruct)
{
    QSPI->CTRL0_B.CLKPHA = configStruct->clockPhase;
    QSPI->CTRL0_B.CLKPOL = configStruct->clockPolarity;
    QSPI->CTRL0_B.FRF = configStruct->frameFormat;
    QSPI->CTRL0_B.DFS = configStruct->dataFrameSize;;
    QSPI->CTRL0_B.SSTEN = configStruct->selectSlaveToggle;
    
    QSPI->BR = configStruct->clockDiv;
    
}

/*!
 * @brief       Fills each configStruct member with its default value
 *
 * @param       configStruct:   Pointer to a QSPI_ConfiStruct_T structure which will be initialized
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_ConfigStructInit(QSPI_ConfiStruct_T *configStruct)
{
    configStruct->clockPhase = QSPI_CLKPHA_2EDGE;
    configStruct->clockPolarity = QSPI_CLKPOL_LOW;
    configStruct->clockDiv = 0;

    configStruct->frameFormat = QSPI_FRF_STANDARD;
    configStruct->dataFrameSize = QSPI_DFS_8BIT;
    configStruct->selectSlaveToggle = QSPI_SST_DISABLE;
}

/*!
 * @brief       Set transmission mode
 *
 * @param       mode:   Specifies the transmission mode
 *                      The parameter can be one of following values:
 *                      @arg QSPI_TRANS_MODE_TX_RX:           TX and RX mode
 *                      @arg QSPI_TRANS_MODE_TX:              TX mode only
 *                      @arg QSPI_TRANS_MODE_RX:              RX mode only
 *                      @arg QSPI_TRANS_MODE_EEPROM_READ:     EEPROM read mode
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetTansMode(QSPI_TRANS_MODE_T mode)
{
    QSPI->CTRL0_B.TXMODE = mode;
}

/*!
 * @brief       Set frame number
 *
 * @param       num:    Specifies the number
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetFrameNum(uint16_t num)
{
    QSPI->CTRL1_B.NDF = num;
}

/*!
 * @brief       Enable QSPI 
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_Enable(void)
{
    QSPI->SSIEN_B.EN = BIT_SET;
}

/*!
 * @brief       Disable QSPI
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_Disable(void)
{
    QSPI->SSIEN_B.EN = BIT_RESET;
}

/*!
 * @brief       Set Tx FIFO threshold
 *
 * @param       num:    Speicifes threshold
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetTxFifoThreshold(uint8_t threshold)
{
    QSPI->TFTL_B.TFTH = threshold;
}

/*!
 * @brief       Set Tx FIFO empty threshold
 *
 * @param       threshold:    Speicifes threshold
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetTxFifoEmptyThreshold(uint8_t threshold)
{
    QSPI->TFTL_B.TFT = threshold;
}

/*!
 * @brief       Read Tx FIFO number of data
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
uint8_t QSPI_ReadTxFifoDataNum(void)
{
    return (uint8_t)QSPI->TFL_B.TFL;
}

/*!
 * @brief       Set rx FIFO threshold
 *
 * @param       threshold:    Speicifes threshold
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetRxFifoThreshold(uint8_t threshold)
{
    QSPI->RFTL_B.RFT = threshold;
}

/*!
 * @brief       Read Rx FIFO number of data
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
uint8_t QSPI_ReadRxFifoDataNum(void)
{
    return (uint8_t)QSPI->RFL_B.RFL;
}

/*!
 * @brief       Read specified QSPI flag
 *
 * @param       flag:   Specifies the flag to be checked
 *                      The parameter can be combination of following values:
 *                      @arg QSPI_FLAG_BUSY:    Busy flag
 *                      @arg QSPI_FLAG_TFNF:    TX FIFO not full flag   
 *                      @arg QSPI_FLAG_TFE:     TX FIFO empty flag        
 *                      @arg QSPI_FLAG_RFNE:    RX FIFO not empty flag           
 *                      @arg QSPI_FLAG_RFF:     RX FIFO full flag  
 *                      @arg QSPI_FLAG_DCE:     Data collision error
 *
 * @retval      The new state of flag (SET or RESET)
 *
 * @note       
 */
uint8_t QSPI_ReadFlag(uint32_t flag)
{
    uint8_t ret = RESET;

    ret = QSPI->STS & flag ? SET : RESET;

    return ret;
}

/*!
 * @brief       Clear specified QSPI flag
 *
 * @param       flag:   Specifies the flag to be cleared
 *                      The parameter can be combination of following values:
 *                      @arg QSPI_FLAG_BUSY:    Busy flag
 *                      @arg QSPI_FLAG_TFNF:    TX FIFO not full flag   
 *                      @arg QSPI_FLAG_TFE:     TX FIFO empty flag        
 *                      @arg QSPI_FLAG_RFNE:    RX FIFO not empty flag           
 *                      @arg QSPI_FLAG_RFF:     RX FIFO full flag  
 *                      @arg QSPI_FLAG_DCE:     Data collision error 
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_ClearFlag(uint32_t flag)
{
    QSPI->STS = (uint32_t)~flag;
}

/*!
 * @brief       Read specified QSPI interrupt flag
 *
 * @param       flag:   Specifies the interrupt flag to be checked
 *                      The parameter can be combination of following values:
 *                      @arg QSPI_INT_FLAG_TFE:     TX FIFO empty interrupt flag
 *                      @arg QSPI_INT_FLAG_TFO:     TX FIFO overflow interrupt flag 
 *                      @arg QSPI_INT_FLAG_RFU:     RX FIFO underflow interrupt flag        
 *                      @arg QSPI_INT_FLAG_RFO:     RX FIFO overflow interrupt flag         
 *                      @arg QSPI_INT_FLAG_RFF:     RX FIFO full interrupt flag  
 *                      @arg QSPI_INT_FLAG_MST:     Master interrupt flag  
 *
 * @retval      The new state of flag (SET or RESET)
 *
 * @note       
 */
uint8_t QSPI_ReadIntFlag(uint32_t flag)
{
    uint8_t ret = RESET;

    ret = QSPI->INTSTS & flag ? SET : RESET;

    return ret;    
}

/*!
 * @brief       Clear specified QSPI interrupt flag
 *
 * @param       flag:   Specifies the interrupt flag to be checked
 *                      The parameter can be one of following values:
 *                      @arg QSPI_INT_FLAG_TFO:     TX FIFO overflow interrupt flag  
 *                      @arg QSPI_INT_FLAG_RFU:     RX FIFO underflow interrupt flag         
 *                      @arg QSPI_INT_FLAG_RFO:     RX FIFO overflow interrupt flag           
 *                      @arg QSPI_INT_FLAG_MST:     Master interrupt flag 
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_ClearIntFlag(uint32_t flag)
{
    volatile uint32_t dummy = 0;
    
    if(flag & QSPI_INT_FLAG_TFO)
    {
        dummy = QSPI->TFOIC;
    }
    else if(flag & QSPI_INT_FLAG_RFO)
    {
        dummy = QSPI->RFOIC;
    }
    else if(flag & QSPI_INT_FLAG_RFU)
    {
        dummy = QSPI->RFUIC;
    }
    else if(flag & QSPI_INT_FLAG_MST)
    {
        dummy = QSPI->MIC;
    }    
}

/*!
 * @brief       Enable the specified QSPI interrupts 
 *
 * @param       interrupt:  Specifies the QSPI interrupt sources
 *                          The parameter can be combination of following values:
 *                          @arg QSPI_INT_TFE:      TX FIFO empty interrupt
 *                          @arg QSPI_INT_TFO:      TX FIFO overflow interrupt  
 *                          @arg QSPI_INT_RFU:      RX FIFO underflow interrupt         
 *                          @arg QSPI_INT_RFO:      RX FIFO overflow interrupt           
 *                          @arg QSPI_INT_RFF:      RX FIFO full interrupt  
 *                          @arg QSPI_INT_MST:      Master interrupt 
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_EnableInterrupt(uint32_t interrupt)
{
    QSPI->INTEN |= interrupt;
}

/*!
 * @brief       Disable the specified QSPI interrupts 
 *
 * @param       interrupt:  Specifies the QSPI interrupt sources
 *                          The parameter can be combination of following values:
 *                          @arg QSPI_INT_TFE:      TX FIFO empty interrupt
 *                          @arg QSPI_INT_TFO:      TX FIFO overflow interrupt  
 *                          @arg QSPI_INT_RFU:      RX FIFO underflow interrupt         
 *                          @arg QSPI_INT_RFO:      RX FIFO overflow interrupt           
 *                          @arg QSPI_INT_RFF:      RX FIFO full interrupt  
 *                          @arg QSPI_INT_MST:      Master interrupt 
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_DisableInterrupt(uint32_t interrupt)
{
    QSPI->INTEN &= (uint32_t)~interrupt;
}

/*!
 * @brief       Set RX sample edge
 *
 * @param       rse:    Specifies the sample edge
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetRxSampleEdge(QSPI_RSE_T rse)
{
    QSPI->RSD_B.RSE = rse;
}

/*!
 * @brief       Set RX sample delay
 *
 * @param       delay:    Specifies the sample delay
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetRxSampleDelay(uint8_t delay)
{
    QSPI->RSD_B.RSD = delay;
}

/*!
 * @brief       Clock stretch enable 
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_EnableClockStretch(void)
{
    QSPI->CTRL2_B.CSEN = BIT_SET;
}

/*!
 * @brief       Clock stretch disable
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_DisableClockStretch(void)
{
    QSPI->CTRL2_B.CSEN = BIT_RESET;
}

/*!
 * @brief       Set wait cycle
 *
 * @param       cycle:    Specifies the wait cycle
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetWaitCycle(uint8_t cycle)
{
    QSPI->CTRL2_B.WAITCYC = cycle;
}

/*!
 * @brief       Set instruction length
 *
 * @param       len:    Specifies the instruction length
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetInstLen(uint8_t len)
{
    QSPI->CTRL2_B.INSLEN = len;
}

/*!
 * @brief       Set address length
 *
 * @param       len:    Specifies the address length
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetAddrLen(uint8_t len)
{
    QSPI->CTRL2_B.ADDRLEN = len;
}

/*!
 * @brief       Set instruction and address type
 *
 * @param       type:   Specifies the instruction and address type
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetInstAddrType(uint8_t type)
{
    QSPI->CTRL2_B.IAT = type;
}

/*!
 * @brief       Set data frame size
 *
 * @param       dfs:    Specifies the data frame size
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetDataFrameSize(QSPI_DFS_T dfs)
{
    QSPI->CTRL0_B.DFS = dfs;
}

/*!
 * @brief       Open QSPI GPIO
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_OpenIO(void)
{
    QSPI->IOSW_B.IOSW = BIT_SET;
}

/*!
 * @brief       Close QSPI GPIO
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_CloseIO(void)
{
    QSPI->IOSW_B.IOSW = BIT_RESET;
}

/*!
 * @brief       Transmit data
 *
 * @param       data:   Data to be transmited
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_TxData(uint32_t data)
{
    QSPI->DATA = data;
}

/*!
 * @brief       Returns the most recent received data
 *
 * @param       None
 *
 * @retval      The received data
 *
 * @note       
 */
uint32_t QSPI_RxData(void)
{
    return (uint32_t)QSPI->DATA;
}

/*!
 * @brief       Enable Slave
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_EnableSlave(void)
{
    QSPI->SLAEN_B.SLAEN = BIT_SET;
}

/*!
 * @brief       Disable slave
 *
 * @param       None
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_DisableSlave(void)
{
    QSPI->SLAEN_B.SLAEN = BIT_RESET;
}

/*!
 * @brief       Set frame format
 *
 * @param       frameFormat
 *
 * @retval      None
 *
 * @note       
 */
void QSPI_SetFrameFormat(QSPI_FRF_T frameFormat)
{
    QSPI->CTRL0_B.FRF = frameFormat;
}

/**@} end of group QSPI_Fuctions*/
/**@} end of group QSPI_Driver */
/**@} end of group Peripherals_Library*/
